Associations
✒️ 2025-05-26 15:09 내용 수정
Node.js 교과서 개정 3판 내용 정리
Associations 종류
- 테이블 간의 1:1, 1:N, N:M 관계를 설정한다.
- 참고 자료 : Sequelize Associations
// A는 source model, B는 target model
A.hasOne(B, { /* option */}); // A는 B 1개를 가짐
A.belongsTo(B, { /* option */}); // A는 B에 의존
A.hasMany(B, { /* option */}); // A는 B 여러 개를 가짐
A.belongsToMany(B, { through: 'C', /* option */}); // A는 C 교차 테이블을 통해 B들에 의존
| Association | 설명 |
|---|---|
| A.hasOne(B) | target model B에 정의된 Foreign key로 연결된 1:1 관계 |
| A.hasMany(B) | target model B에 정의된 Foreign key로 연결된 A와 B 간의 1:N 관계 |
| A.belongsToOne(B) | source model A에 정의된 Foreign key로 연결된 1대1 관계 |
| A.belongsToMany(B, { through: 'C'}) | A와 B의 키를 Foreign key로 가진 연결 테이블 C를 사용한 A와 B 간의 N:M 관계 |
- 1:1 관계
- foreignKey를 따로 옵션에 설정하지 않는다면 Sequelize에선 기본으로 B model에 A model에 대한 Foreign key가 있는 것으로 파악한다.
// 1번째 : hasOne에 설정
A.hasOne(B, {
foreignKey: 'aId'
});
B.belongsTo(A);
// 2번째 : belongsTo에 설정
A.hasOne(B);
B.belongsTo(A, {
foreignKey: 'aId'
});
- 1:N 관계
// 1번째 : hasMany에 설정
A.hasMany(B, {
foreignKey: 'aId'
});
B.belongsTo(A);
// 2번째 : belongsTo에 설정
A.hasMany(B);
B.belongsTo(A, {
foreignKey: 'aId'
});
- N:M 관계
- Sequelize에선 N:M 관계에 필요한 연결 테이블(아래에선 C)를 자동으로 생성한다.
- 참고 자료 : Sequelize Many-To-Many relationships
- 상세한 설명은 아직 구현 시도를 해보지 않아 이해가 어려워 기본 구성만 작성했다.
A.belongsToMany(B, { through : 'C' });
B.belongsToMany(A, { through : 'C' });
연결된 테이블간의 query
- 연결된 테이블에서 query를 수행할 땐 옵션에서 include로 대상 테이블과 포함할 column을 선택한다.
A.hasOne(B);
B.belongsTo(A);
const test = await A.findOne({
where : {
name : 'test'
},
include: B
});
Association 설정
- index.js에 associate 설정을 추가한다.
npm sequelize init수행 후 자동 생성되는 index.js에서 일부 옵션을 수정한 형태다.- model 폴더에 model 파일만 넣어야 하며, 미완성 모델이 있으면 에러가 발생할 수 있다.
'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const process = require('process');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) { // Sequelize 객체 생성
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => { // 숨김 파일, index.js, js 확장자가 아닌 파일 필터링
return (
file.indexOf('.') !== 0 &&
file !== basename &&
file.slice(-3) === '.js' &&
file.indexOf('.test.js') === -1
);
})
.forEach(file => { // 해당 파일의 Model을 불러온 후 init
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => { // associate 호출
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
- Model 파일에 associate 함수 내에 테이블간 관계를 지정한다.
- 실습에선 Blog 테이블과 User 테이블을 1(User):N(Blog) 관계로 설정했다.
// User 테이블 모델
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate(models) {
this.hasMany(models.Blog, { // Blog 테이블과의 관계
sourceKey: 'id',
foreignKey: 'user_id',
})
}
}
User.init({
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
username: DataTypes.STRING,
password: DataTypes.STRING
}, {
sequelize,
modelName: 'User',
});
return User;
};
// Blog 테이블 모델
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Blog extends Model {
static associate(models) {
this.belongsTo(models.User, { // User 테이블과의 관계
targetKey: 'id',
foreignKey: 'user_id',
})
}
}
Blog.init({
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
user_id : DataTypes.INTEGER,
title: DataTypes.STRING,
content: DataTypes.STRING
}, {
sequelize,
modelName: 'Blog',
});
return Blog;
};
- query문 작성 시 include 옵션으로 join을 수행한다.
const result = await Blog.findAndCountAll({
where: {
user_id: inputId
},
include: [{
model: User,
attributes: ['username']
}],
offset,
limit
});
const pages = result.count;
const data = result.rows;